/*
* Poppy Game Engine - https://pgetemplate.googlecode.com/svn/
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* Copyright (c) 2008 Poppy
*/

#pragma once

#include "MainExportSymbol.h"
#include "SystemDefines.h"

namespace PGEMain
{

	struct CStringAData
	{
		long nRefs;
		int nDataLength;
		int nAllocLength;
		char* data() { return (char*)(this+1); }
	};

	class PGEMAIN_API CStringA
	{

	public:

		CStringA();
		CStringA(const CStringA& stringSrc);
		CStringA(char ch, int nLength =1);
		CStringA(LPCSTR lpsz);
		CStringA(LPCSTR lpch, int nLength);
		CStringA(const BYTE* psz);
		~CStringA();

		int GetLength() const;
		int GetAllocLength() const;
		bool IsEmpty() const;
		operator LPCSTR() const;
		void Empty();

		const CStringA& operator = (const CStringA& stringSrc);
		const CStringA& operator = (LPCSTR lpsz);
		const CStringA& operator = (char ch);
		const CStringA& operator += (const CStringA& string);
		const CStringA& operator += (char ch);
		const CStringA& operator += (LPCSTR lpsz);
		char operator [] (int nIndex) const;

		friend CStringA operator + (const CStringA& string1,const CStringA& string2);
		friend CStringA operator + (const CStringA& string, char ch);
		friend CStringA operator + (char ch, const CStringA& string);
		friend CStringA operator + (const CStringA& string, LPCSTR lpsz);
		friend CStringA operator + (LPCSTR lpsz, const CStringA& string);

		int Delete(int nIndex, int nCount = 1);
		int Insert(int nIndex, char ch);
		int Insert(int nIndex, LPCSTR pstr);
		int Replace(LPCSTR lpszOld, LPCSTR lpszNew);
		int Replace(char chOld, char chNew);
		int Remove(char chRemove);
		void TrimRight(LPCSTR lpszTargetList);
		void TrimRight(char chTarget);
		void TrimRight();
		void TrimLeft(LPCSTR lpszTargets);
		void TrimLeft(char chTarget);
		void TrimLeft();

		void SetAt(int nIndex, char ch);
		char GetAt(int nIndex) const;
		CStringA Mid(int nFirst) const;
		CStringA Mid(int nFirst, int nCount) const;
		CStringA Right(int nCount) const;
		CStringA Left(int nCount) const;
		void MakeUpper();
		void MakeLower();
		void MakeReverse();

		int Find(char ch) const;
		int Find(char ch, int nStart) const;
		int ReverseFind(char ch) const;
		int Find(LPCSTR lpszSub) const;
		int Find(LPCSTR lpszSub, int nStart) const;
		int FindOneOf(LPCSTR lpszCharSet) const;

		LPSTR GetBuffer(int nMinBufLength);
		void ReleaseBuffer(int nNewLength=-1);
		LPSTR GetBufferSetLength(int nNewLength);
		void FreeExtra();
		LPSTR LockBuffer();
		void UnlockBuffer();
		
		int Compare(LPCSTR lpsz) const;
		int CompareNoCase(LPCSTR lpsz) const;
		
		int Collate(LPCSTR lpsz) const;

		void Format(LPCSTR lpszFormat, ...);

	protected:

		void Init();
		CStringAData* GetData() const;
		void AllocBuffer(int nLen);
		void CopyBeforeWrite();
		void AllocBeforeWrite(int nLen);
		void AssignCopy(int nSrcLen, LPCSTR lpszSrcData);
		
		void AllocCopy(CStringA& dest, int nCopyLen, int nCopyIndex,int nExtraLen) const;
		void Release();

		#ifdef WIN32
		typedef char* psp_va_list;
		#endif
		#ifdef PSP
		typedef void* psp_va_list;
		#endif

		void FormatV(LPCSTR lpszFormat, psp_va_list argList);
		void ConcatCopy(int nSrc1Len, LPCSTR lpszSrc1Data, int nSrc2Len, LPCSTR lpszSrc2Data);
		void ConcatInPlace(int nSrcLen, LPCSTR lpszSrcData);

		static void  Release(CStringAData* pData);
		static void FreeData(CStringAData* pData);
		static int SafeStrlen(LPCSTR lpsz);
		LPSTR m_pchData;

	};

	bool PGEMAIN_API operator==(const CStringA& s1, const CStringA& s2);
	bool PGEMAIN_API operator==(const CStringA& s1, LPCSTR s2);
	bool PGEMAIN_API operator==(LPCSTR s1, const CStringA& s2);
	bool PGEMAIN_API operator!=(const CStringA& s1, const CStringA& s2);
	bool PGEMAIN_API operator!=(const CStringA& s1, LPCSTR s2);
	bool PGEMAIN_API operator!=(LPCSTR s1, const CStringA& s2);
	bool PGEMAIN_API operator<(const CStringA& s1, const CStringA& s2);
	bool PGEMAIN_API operator<(const CStringA& s1, LPCSTR s2);
	bool PGEMAIN_API operator<(LPCSTR s1, const CStringA& s2);
	bool PGEMAIN_API operator>(const CStringA& s1, const CStringA& s2);
	bool PGEMAIN_API operator>(const CStringA& s1, LPCSTR s2);
	bool PGEMAIN_API operator>(LPCSTR s1, const CStringA& s2);
	bool PGEMAIN_API operator<=(const CStringA& s1, const CStringA& s2);
	bool PGEMAIN_API operator<=(const CStringA& s1, LPCSTR s2);
	bool PGEMAIN_API operator<=(LPCSTR s1, const CStringA& s2);
	bool PGEMAIN_API operator>=(const CStringA& s1, const CStringA& s2);
	bool PGEMAIN_API operator>=(const CStringA& s1, LPCSTR s2);
	bool PGEMAIN_API operator>=(LPCSTR s1, const CStringA& s2);

	void ConstructElements(CStringA* pElements, int nCount);
	void DestructElements(CStringA* pElements, int nCount);
	void CopyElements(CStringA* pDest, const CStringA* pSrc, int nCount);

}
